"""
混合分类器

结合规则分类和AI分类的混合分类器。
"""

import time
from typing import Dict, List, Any, Optional
from datetime import datetime
import logging

from src.core.di import Injectable, Inject
from src.modules.scanners.base import FileInfo, FileType, FileCategory
from src.modules.scanners.file_classifier import SmartFileClassifier
from .base import AIClassifier, ClassificationResult
from .gemini_classifier import GeminiVideoClassifier


@Injectable(scope="singleton")
class HybridClassifier(AIClassifier):
    """
    混合分类器
    
    结合规则分类和AI分类，提供最佳的分类效果。
    """
    
    def __init__(self,
                 rule_classifier: SmartFileClassifier = Inject(SmartFileClassifier),
                 gemini_classifier: GeminiVideoClassifier = Inject(GeminiVideoClassifier),
                 config: Dict[str, Any] = Inject("config"),
                 logger: logging.Logger = Inject("logger")):
        self.rule_classifier = rule_classifier
        self.gemini_classifier = gemini_classifier
        self.config = config
        self.logger = logger
        
        # 混合分类器配置
        self.ai_config = config.get("ai_classifier", {})
        self.enable_gemini = self.ai_config.get("enable_gemini", True)
        self.confidence_threshold = self.ai_config.get("confidence_threshold", 0.7)
        self.fallback_to_rules = self.ai_config.get("fallback_to_rules", True)
        
        # 分类策略
        self.classification_strategy = self.ai_config.get("strategy", "ai_first")  # ai_first, rules_first, parallel
    
    @property
    def name(self) -> str:
        return "hybrid_classifier"
    
    @property
    def version(self) -> str:
        return "1.0.0"
    
    @property
    def supported_file_types(self) -> List[str]:
        return ["video", "audio", "image", "mp4", "avi", "mov", "mkv", "webm", "mp3", "wav", "jpg", "png"]
    
    def is_available(self) -> bool:
        """检查分类器是否可用"""
        # 至少有一个分类器可用
        return (
            (self.enable_gemini and self.gemini_classifier.is_available()) or
            self.rule_classifier is not None
        )
    
    async def classify(self, file_info: FileInfo, **kwargs) -> ClassificationResult:
        """混合分类文件"""
        start_time = time.time()
        
        try:
            if self.classification_strategy == "ai_first":
                return await self._classify_ai_first(file_info, **kwargs)
            elif self.classification_strategy == "rules_first":
                return await self._classify_rules_first(file_info, **kwargs)
            elif self.classification_strategy == "parallel":
                return await self._classify_parallel(file_info, **kwargs)
            else:
                raise ValueError(f"未知的分类策略: {self.classification_strategy}")
                
        except Exception as e:
            processing_time = time.time() - start_time
            error_msg = f"混合分类失败: {e}"
            self.logger.error(error_msg)
            
            return ClassificationResult(
                success=False,
                error=error_msg,
                classifier_type=self.name,
                processing_time=processing_time,
                timestamp=datetime.now()
            )
    
    async def _classify_ai_first(self, file_info: FileInfo, **kwargs) -> ClassificationResult:
        """AI优先分类策略"""
        # 1. 首先尝试AI分类（仅对视频文件）
        if (file_info.file_type == FileType.VIDEO and 
            self.enable_gemini and 
            self.gemini_classifier.is_available()):
            
            ai_result = await self.gemini_classifier.classify(file_info, **kwargs)
            
            # 如果AI分类成功且置信度足够高
            if ai_result.success and ai_result.confidence >= self.confidence_threshold:
                ai_result.metadata.update({
                    "hybrid_strategy": "ai_first",
                    "primary_classifier": "gemini"
                })
                return ai_result
            
            # AI分类失败或置信度不够，记录结果用于后续合并
            ai_partial_result = ai_result
        else:
            ai_partial_result = None
        
        # 2. 使用规则分类作为回退或主要方法
        rule_result = await self._get_rule_classification(file_info, **kwargs)
        
        # 3. 合并结果
        if ai_partial_result and ai_partial_result.success:
            return self._merge_classifications(rule_result, ai_partial_result, "ai_first")
        else:
            rule_result.metadata.update({
                "hybrid_strategy": "ai_first",
                "primary_classifier": "rules",
                "ai_fallback_reason": "AI不可用或失败"
            })
            return rule_result
    
    async def _classify_rules_first(self, file_info: FileInfo, **kwargs) -> ClassificationResult:
        """规则优先分类策略"""
        # 1. 首先使用规则分类
        rule_result = await self._get_rule_classification(file_info, **kwargs)
        
        # 2. 如果规则分类置信度不够高，尝试AI增强
        if (rule_result.confidence < self.confidence_threshold and
            file_info.file_type == FileType.VIDEO and
            self.enable_gemini and
            self.gemini_classifier.is_available()):
            
            ai_result = await self.gemini_classifier.classify(file_info, **kwargs)
            
            if ai_result.success:
                return self._merge_classifications(rule_result, ai_result, "rules_first")
        
        rule_result.metadata.update({
            "hybrid_strategy": "rules_first",
            "primary_classifier": "rules"
        })
        return rule_result
    
    async def _classify_parallel(self, file_info: FileInfo, **kwargs) -> ClassificationResult:
        """并行分类策略"""
        import asyncio
        
        tasks = []
        
        # 添加规则分类任务
        tasks.append(self._get_rule_classification(file_info, **kwargs))
        
        # 添加AI分类任务（仅对视频文件）
        if (file_info.file_type == FileType.VIDEO and 
            self.enable_gemini and 
            self.gemini_classifier.is_available()):
            tasks.append(self.gemini_classifier.classify(file_info, **kwargs))
        
        # 并行执行
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        rule_result = results[0] if len(results) > 0 else None
        ai_result = results[1] if len(results) > 1 and not isinstance(results[1], Exception) else None
        
        # 合并结果
        if ai_result and ai_result.success and rule_result:
            return self._merge_classifications(rule_result, ai_result, "parallel")
        elif rule_result:
            rule_result.metadata.update({
                "hybrid_strategy": "parallel",
                "primary_classifier": "rules"
            })
            return rule_result
        else:
            return ClassificationResult(
                success=False,
                error="所有分类器都失败了",
                classifier_type=self.name,
                timestamp=datetime.now()
            )
    
    async def _get_rule_classification(self, file_info: FileInfo, **kwargs) -> ClassificationResult:
        """获取规则分类结果"""
        try:
            # 使用现有的规则分类器
            classified_file = await self.rule_classifier.classify(file_info)
            
            # 转换为ClassificationResult格式
            return ClassificationResult(
                category=classified_file.category,
                confidence=classified_file.confidence,
                reasoning="基于规则的分类",
                features=classified_file.tags,
                classifier_type="rules",
                model_name="rule_based",
                processing_time=0.1,  # 规则分类很快
                timestamp=datetime.now(),
                metadata={
                    "rules_matched": len(classified_file.tags),
                    "file_patterns_matched": True,
                    "path_patterns_matched": True
                },
                success=True
            )
            
        except Exception as e:
            return ClassificationResult(
                success=False,
                error=f"规则分类失败: {e}",
                classifier_type="rules",
                timestamp=datetime.now()
            )
    
    def _merge_classifications(self, 
                             rule_result: ClassificationResult, 
                             ai_result: ClassificationResult, 
                             strategy: str) -> ClassificationResult:
        """合并分类结果"""
        
        # 如果两个分类器得出相同结果，提高置信度
        if rule_result.category == ai_result.category:
            merged_confidence = min(1.0, (rule_result.confidence + ai_result.confidence) / 2 + 0.2)
            
            return ClassificationResult(
                category=rule_result.category,
                confidence=merged_confidence,
                reasoning=f"规则和AI分类一致: {rule_result.reasoning} | {ai_result.reasoning}",
                features=list(set(rule_result.features + ai_result.features)),
                classifier_type=self.name,
                model_name=f"hybrid_{strategy}",
                processing_time=rule_result.processing_time + ai_result.processing_time,
                timestamp=datetime.now(),
                metadata={
                    "hybrid_strategy": strategy,
                    "agreement": True,
                    "rule_result": rule_result.to_dict(),
                    "ai_result": ai_result.to_dict(),
                    "confidence_boost": 0.2
                },
                success=True
            )
        
        # 如果结果不同，选择置信度更高的
        else:
            if ai_result.confidence > rule_result.confidence:
                primary_result = ai_result
                secondary_result = rule_result
                primary_type = "ai"
            else:
                primary_result = rule_result
                secondary_result = ai_result
                primary_type = "rules"
            
            return ClassificationResult(
                category=primary_result.category,
                confidence=primary_result.confidence,
                reasoning=f"选择{primary_type}分类结果: {primary_result.reasoning}",
                features=primary_result.features,
                classifier_type=self.name,
                model_name=f"hybrid_{strategy}",
                processing_time=rule_result.processing_time + ai_result.processing_time,
                timestamp=datetime.now(),
                metadata={
                    "hybrid_strategy": strategy,
                    "agreement": False,
                    "primary_classifier": primary_type,
                    "rule_result": rule_result.to_dict(),
                    "ai_result": ai_result.to_dict(),
                    "selection_reason": "higher_confidence"
                },
                success=True
            )
    
    async def get_detailed_analysis(self, file_info: FileInfo, **kwargs) -> Dict[str, Any]:
        """获取详细的分析结果"""
        import asyncio
        
        # 并行运行所有可用的分类器
        tasks = []
        
        # 规则分类
        tasks.append(("rules", self._get_rule_classification(file_info, **kwargs)))
        
        # AI分类（如果可用）
        if (file_info.file_type == FileType.VIDEO and 
            self.enable_gemini and 
            self.gemini_classifier.is_available()):
            tasks.append(("gemini", self.gemini_classifier.classify(file_info, **kwargs)))
        
        # 执行所有任务
        results = {}
        for name, task in tasks:
            try:
                result = await task
                results[name] = result.to_dict()
            except Exception as e:
                results[name] = {"success": False, "error": str(e)}
        
        # 获取最终的混合分类结果
        final_result = await self.classify(file_info, **kwargs)
        
        return {
            "file_info": file_info.to_dict(),
            "individual_results": results,
            "final_result": final_result.to_dict(),
            "analysis_timestamp": datetime.now().isoformat()
        }
